Find tooltip/dnd widget running through container children in inverse order
authorCarlos Garnacho <carlosg@gnome.org>
Mon, 29 Apr 2013 17:25:21 +0000 (19:25 +0200)
committerMatthias Clasen <mclasen@redhat.com>
Mon, 13 May 2013 01:17:01 +0000 (21:17 -0400)
Usually, educated GtkContainers' forall() implementation returns children
in an order that's safe for the default draw() implementation in GtkContainer.
So for widgets with some stacking notions (eg. GtkOverlay),
_gtk_widget_find_at_coords() needs to recurse within containers in reverse
order so it finds the topmost widget.

As this function is used in both tooltips and DnD code, this improves behavior
of "floating" widgets wrt those two. This could for example be seen in the
"Transparent" GTK+ demo, where dropping text on the entry results on the text
going to the textview.

https://bugzilla.gnome.org/show_bug.cgi?id=699239

gtk/gtktooltip.c

index aba9ffb38a173b8be9a9a377bc19c76c4c9f05d2..0914641c5d3ef01f53ff75cb7d491fe11ef08309 100644 (file)
@@ -691,6 +691,15 @@ struct ChildLocation
   gint y;
 };
 
+static void
+prepend_and_ref_widget (GtkWidget *widget,
+                        gpointer   data)
+{
+  GSList **slist_p = data;
+
+  *slist_p = g_slist_prepend (*slist_p, g_object_ref (widget));
+}
+
 static void
 child_location_foreach (GtkWidget *child,
                        gpointer   data)
@@ -735,6 +744,7 @@ child_location_foreach (GtkWidget *child,
          if (GTK_IS_CONTAINER (child))
            {
              struct ChildLocation tmp = { NULL, NULL, 0, 0 };
+              GSList *children = NULL, *tmp_list;
 
              /* Take (x, y) relative the child's allocation and
               * recurse.
@@ -744,12 +754,20 @@ child_location_foreach (GtkWidget *child,
              tmp.container = child;
 
              gtk_container_forall (GTK_CONTAINER (child),
-                                   child_location_foreach, &tmp);
+                                   prepend_and_ref_widget, &children);
+
+              for (tmp_list = children; tmp_list; tmp_list = tmp_list->next)
+                {
+                  child_location_foreach (tmp_list->data, &tmp);
+                  g_object_unref (tmp_list->data);
+                }
 
              if (tmp.child)
                child_loc->child = tmp.child;
              else
                child_loc->child = child;
+
+              g_slist_free (children);
            }
          else
            child_loc->child = child;